package org.springblade.modules.meter.job;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springblade.common.utils.CommonUtil;
import org.springblade.core.tool.constant.BladeConstant;
import org.springblade.modules.meter.entity.*;
import org.springblade.modules.meter.mapper.*;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.List;

/**
 * @author: John
 * @DateTme: 2020/08/01 16:09
 * 每日计算电量电费
 */
@Component
public class MeterSchedule {

    /*@Resource
    UserMapper userMapper;*/

    @Resource
	DeviceMapper ammeterMapper;

    @Resource
	SectionPriceMapper sectionPriceMapper;

    @Resource
	MeterCostMapper costMapper;

    @Resource
	MeterUsageMapper usageMapper;

    @Resource
	LadderedPriceMapper ladderedPriceMapper;


    @Scheduled(cron = "0 0 0 * * ?")
    public void refreshMonthAmount(){
        List<Device> ammeterList = ammeterMapper.selectList(Wrappers.<Device>query().lambda().eq(Device::getIsDeleted, BladeConstant.DB_NOT_DELETED));
        ammeterList.parallelStream().forEach(ammeter -> process(ammeter));
    }

    @Transactional
    public void process(Device ammeter){
        BigDecimal dayUsage = ammeter.getReadValue().subtract(ammeter.getPreReadValue());
        dayUsage = dayUsage.compareTo(BigDecimal.ZERO) == -1 ? BigDecimal.ZERO : dayUsage;
        ammeter.setPreReadTime(ammeter.getReadTime());
        ammeter.setPreReadValue(ammeter.getReadValue());
        ammeter.setOnline(1);

        MeterUsage ammeterUsage = new MeterUsage();
        ammeterUsage.setMeterNo(ammeter.getSn());
        //ammeterUsage.setReadDate(CommonUtil.getNewYesterday());
        //ammeterUsage.setReadTime(ammeterUsage.getReadDate().toInstant(ZoneOffset.of("+8")).toEpochMilli());
		ammeterUsage.setReadTime(LocalDateTime.now());
        ammeterUsage.setReadValue(ammeter.getReadValue());

        long uid = ammeter.getCreateUser();
        MeterCost ammeterCost = new MeterCost();
        ammeterCost.setMeterNo(ammeter.getSn());
        ammeterCost.setCreateUser(uid);
        //ammeterCost.setCostDate(CommonUtil.getNewYesterday());
        ammeterCost.setCostTime(CommonUtil.getNewYesterday());
        ammeterCost.setCreateDept(ammeter.getCreateDept());

        // 是否开始计费
        if(ammeter.getFeeStatus() == 1){
            ammeter.setMonthAmount(ammeter.getMonthAmount().add(dayUsage));
            ammeterUsage.setMeterUsage(dayUsage);
            ammeterCost.setMeterUsage(dayUsage);
            BigDecimal cost = BigDecimal.ZERO;
            int priceType = ammeter.getPriceType();
            if(priceType==0) { //普通计费
                int voltageType = ammeter.getVoltageType();
                // TODO 根据模板id获取对应的单个电价列表
                LadderedPrice singlePrice = ladderedPriceMapper.getSingleLadder(ammeter.getCreateDept().toString(), voltageType, 1);
                cost = getNormalCost(singlePrice, dayUsage);
                ammeterCost.setCostMoney(cost);
            } else if(priceType==1) { //阶梯计费
                int voltageType = ammeter.getVoltageType();
                // TODO 根据模板id获取对应的阶梯电价列表
                List<LadderedPrice> levels = ladderedPriceMapper.getPriceList(ammeter.getCreateDept().toString(), voltageType);
                cost = getLadderCost(levels, dayUsage, ammeter.getMonthAmount());
                ammeterCost.setCostMoney(cost);
            } else if(priceType==2) { //分时段计费
                BigDecimal sharpDailyUsage = ammeter.getSharpReadValue().subtract(ammeter.getPreSharpReadValue());
                BigDecimal peekDailyUsage = ammeter.getPeekReadValue().subtract(ammeter.getPrePeekReadValue());
                BigDecimal flatDailyUsage = ammeter.getFlatReadValue().subtract(ammeter.getPreFlatReadValue());
                BigDecimal lowDailyUsage = ammeter.getLowReadValue().subtract(ammeter.getPreLowReadValue());
                ammeter.setPreSharpReadValue(ammeter.getSharpReadValue());
                ammeter.setPreSharpReadTime(ammeter.getSharpReadTime());
                ammeter.setPrePeekReadValue(ammeter.getPeekReadValue());
                ammeter.setPrePeekReadTime(ammeter.getPeekReadTime());
                ammeter.setPreFlatReadValue(ammeter.getFlatReadValue());
                ammeter.setPreFlatReadTime(ammeter.getFlatReadTime());
                ammeter.setPreLowReadValue(ammeter.getLowReadValue());
                ammeter.setPreLowReadTime(ammeter.getLowReadTime());
                ammeterUsage.setSharpUsage(sharpDailyUsage);
                ammeterUsage.setPeekUsage(peekDailyUsage);
                ammeterUsage.setFlatUsage(flatDailyUsage);
                ammeterUsage.setLowUsage(lowDailyUsage);
                // 查询分时段 计价费率  TODO 根据模板id获取对应的电价列表
                List<SectionPrice> rates = sectionPriceMapper.getSectionPriceList(ammeter.getCreateDept().toString());
                BigDecimal sharpPrice = BigDecimal.ZERO;
                BigDecimal peekPrice = BigDecimal.ZERO;
                BigDecimal flatPrice = BigDecimal.ZERO;
                BigDecimal lowPrice = BigDecimal.ZERO;
                for(SectionPrice rate : rates) {
                    if(rate.getRateType() == 0) sharpPrice = rate.getRatePrice();
                    if(rate.getRateType() == 1) peekPrice = rate.getRatePrice();
                    if(rate.getRateType() == 2) flatPrice = rate.getRatePrice();
                    if(rate.getRateType() == 3) lowPrice = rate.getRatePrice();
                }
                BigDecimal sharpCost = sharpDailyUsage.multiply(sharpPrice);
                BigDecimal peekCost = peekDailyUsage.multiply(peekPrice);
                BigDecimal flatCost = flatDailyUsage.multiply(flatPrice);
                BigDecimal lowCost = lowDailyUsage.multiply(lowPrice);
                cost = sharpCost.add(peekCost).add(flatCost).add(lowCost);
                ammeterCost.setCostMoney(cost);
                ammeterCost.setSharpUsage(sharpDailyUsage);
                ammeterCost.setPeekUsage(peekDailyUsage);
                ammeterCost.setFlatUsage(flatDailyUsage);
                ammeterCost.setLowUsage(lowDailyUsage);
                ammeterCost.setSharpCost(sharpCost);
                ammeterCost.setPeekCost(peekCost);
                ammeterCost.setFlatCost(flatCost);
                ammeterCost.setLowCost(lowCost);
            } else {
                ammeterCost.setCostMoney(BigDecimal.ZERO);
            }
			// TODO 更新 账户 余额
            /*User user = userMapper.findByUid(uid);
            user.setAccountBalance(user.getAccountBalance().subtract(cost));
            userMapper.saveUser(user);*/

        } else {
            if((System.currentTimeMillis()/1000 - ammeter.getReadTime().toInstant(ZoneOffset.of("+8")).toEpochMilli()) / 24 * 3600 >= 2) {
                ammeter.setOnline(0);
            }
            ammeterUsage.setMeterUsage(BigDecimal.ZERO);
            ammeterCost.setCostMoney(BigDecimal.ZERO);
            ammeterCost.setMeterUsage(BigDecimal.ZERO);
        }

        // TODO 更新设备数值
        /*meterMapper.uptAmmeterValue(ammeter);*/
        usageMapper.insert(ammeterUsage);
        costMapper.insert(ammeterCost);
    }

    private BigDecimal getNormalCost(LadderedPrice ladder, BigDecimal dayUsage) {
        return dayUsage.multiply(ladder.getPrice());
    }

    private BigDecimal getLadderCost(List<LadderedPrice> list, BigDecimal dayUsage, BigDecimal monthAmount){
        int levelCnt = list.size();
        BigDecimal[] prices = new BigDecimal[levelCnt];   //阶梯电费单价
        BigDecimal[] ladders = new BigDecimal[levelCnt];  //阶梯电费起始kwh
        for(int i = 0; i < levelCnt; i++){
            prices[i] = list.get(i).getPrice();
            ladders[i] = list.get(i).getLadder();
        }
        BigDecimal cost = BigDecimal.ZERO;
        int curLevel = levelCnt-1;
        for(; curLevel >=0 ;curLevel--){
            if(monthAmount.compareTo(ladders[curLevel]) == 1) break;
        }

        BigDecimal excludeToday = monthAmount.subtract(dayUsage);
        if(curLevel == 0) {
            cost = dayUsage.multiply(prices[0]);
        } else {
            boolean isLower = excludeToday.compareTo(ladders[curLevel]) == -1;
            if(isLower){
                BigDecimal beyond = monthAmount.subtract(ladders[curLevel]);
                BigDecimal rest = dayUsage.subtract(beyond);
                BigDecimal higher = beyond.multiply(prices[curLevel]);
                BigDecimal lower = rest.multiply(prices[curLevel-1]);
                cost = higher.add(lower);
            } else {
                cost = dayUsage.multiply(prices[curLevel]);
            }
        }
        return cost;
    }


}
